package fi.uba.algocontrol.view;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.*;

import fi.uba.algocontrol.controller.AvionController;
import fi.uba.algocontrol.model.Mapa;
import fi.uba.algocontrol.model.ObjetoPosicionableGenerico;
import fi.uba.algocontrol.model.Vector;
import fi.uba.algocontrol.model.aviones.Avion;
import fi.uba.algocontrol.model.niveles.Puntaje;
import fi.uba.algocontrol.observer.AvionObserver;
import fi.uba.algocontrol.observer.ColisionObserver;
import fi.uba.algocontrol.view.factory.PistaViewFactory;
import fiuba.algo3.titiritero.dibujables.SuperficiePanel;
import fiuba.algo3.titiritero.modelo.GameLoop;
import fiuba.algo3.titiritero.modelo.SuperficieDeDibujo;

public class VentanaPrincipal {

	private JFrame frame;
	private GameLoop gameLoop;
    private Mapa mapa;
    private AvionController avionController;
    private JuegoView juegoView;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					VentanaPrincipal window = new VentanaPrincipal();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public VentanaPrincipal() {
		try {
			initialize();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Initialize the contents of the frame.
	 * @throws IOException 
	 */
	private void initialize() throws IOException {
		frame = new JFrame();
		frame.setForeground(new Color(0, 0, 0));
		frame.setBounds(100, 100, 900, 700);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(null);
		frame.setTitle("Algo Control - Algoritmos III FIUBA - Grupo 3, 2012");
		
		JButton btnIniciar = this.addBotonIniciar();
        JButton btnReiniciar = this.addBotonReiniciar();
        JButton btnDetener = this.addBotonDetener();
		JPanel panel       = this.addSuperficiePanel();
        JLabel labelPuntaje = this.addLabelPuntaje();
		
		this.gameLoop = new GameLoop((SuperficieDeDibujo) panel);
        this.gameLoop.setFrecuencia(100);

        this.inicializarModelo(); //inicializo modelo
        this.inicializarVista(); //inicializo vista del juego
        this.inicializarControlador(); //inicializo controlador

        this.agregarObservadores(); //agrego observadores al gameloop

		this.addMouseListener(panel);
		
		this.addKeyListener();

        Puntaje.getInstance().agregarListener( new PuntajeListenerImpl(labelPuntaje) );

		this.setComponentsFocus(btnIniciar, btnDetener);

	}

    private void agregarObservadores()
    {
        AvionObserver avionObserver = new AvionObserver(this.gameLoop, this.mapa, this.juegoView, this.avionController);
        this.gameLoop.agregarObservador( avionObserver );
        ColisionObserver colisionObserver = new ColisionObserver(this.gameLoop, this.mapa, this.juegoView);
        this.gameLoop.agregarObservador( colisionObserver );
    }

    private void inicializarModelo()
    {
        this.mapa = new Mapa();
        Puntaje.getInstance().reiniciar();
    }

    private void inicializarControlador()
    {
        this.avionController = new AvionController(this.mapa);
    }

	private void inicializarVista()
    {
        this.juegoView = new JuegoView();
        PistaViewFactory pistaViewFactory = new PistaViewFactory(juegoView, mapa);

        pistaViewFactory.agregarPistasSimples(2);
        pistaViewFactory.agregarPistasLargas(1);
        pistaViewFactory.agregarHelipuertos(1);

        this.gameLoop.agregar(juegoView);
	}

	private void setComponentsFocus(JButton btnIniciar, JButton btnDetener) {
		frame.setFocusable(true);
		btnDetener.setFocusable(false);
		btnIniciar.setFocusable(false);
	}

	private void addKeyListener() {
		frame.addKeyListener(new KeyListener(
				) {
			
			@Override
			public void keyTyped(KeyEvent keyEvent) {

			}

			@Override
			public void keyReleased(KeyEvent arg0) {
			}
			
			@Override
			public void keyPressed(KeyEvent keyEvent) {
				System.out.println("Ping");

                //Reinicio de juego, tecla R
                if (!gameLoop.estaEjecutando() && (String.valueOf(keyEvent.getKeyChar())).toLowerCase().equals("r"))
                {
                    System.out.println("TECLA R");
                    try
                    {
                        initialize();
                        gameLoop.iniciarEjecucion();
                    }catch(Exception e)
                    {

                    }
                }
			}  
			 	
		});
	}

	private void addMouseListener(JPanel panel) {
		panel.addMouseListener(
                new MouseAdapter()
        {
					
			@Override
			public void mouseClicked(MouseEvent mouseEvent)
            {
                Point point = mouseEvent.getPoint();
                Vector puntoVector = new Vector(point.getX(), point.getY());

                //Obtengo el avion que esta seleccionado
                Avion avionSeleccionadoAnterior = avionController.getAvionSeleccionado();

                //Envio el punto donde se clickeo a cada vista de avion para que cada una determine si fue seleccionada.
                for(AvionView avionView : juegoView.getAvionesView())
                    avionView.meSeleccionaron(puntoVector);

                //Si el avion seleccionado no es null y el seleccionado anterior es igual al seleccionado actual
                //Entonces se clickeó en un punto del mapa ( No avion ) y se envia el mensaje al avion seleccionado
                //para que modifique su direccion
                if (avionController.getAvionSeleccionado() != null &&
                        avionSeleccionadoAnterior == avionController.getAvionSeleccionado())
                    avionController.dirigirAvionSeleccionado(puntoVector);
			}
        });
	}

	private JPanel addSuperficiePanel() {
		JPanel panel = new SuperficiePanel();
		panel.setBackground(new Color(180, 180, 180));
		panel.setBounds(42, 53, Mapa.getAncho(), Mapa.getAlto());
		frame.getContentPane().add(panel);
		return panel;
	}

    private JButton addBotonIniciar() {
        JButton btnIniciar = new JButton("Iniciar");
        btnIniciar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {

                if (!gameLoop.estaEjecutando())
                    gameLoop.iniciarEjecucion();
            }
        });
        btnIniciar.setBounds(42, 16, 77, 25);
        frame.getContentPane().add(btnIniciar);
        return btnIniciar;
    }

	private JButton addBotonDetener() {
		JButton btnDetener = new JButton("Detener");
		btnDetener.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				gameLoop.detenerEjecucion();
			}
		});
		btnDetener.setBounds(150, 16, 92, 25);
		frame.getContentPane().add(btnDetener);
		return btnDetener;
	}

    private JButton addBotonReiniciar() {
        JButton btnIniciar = new JButton("Reiniciar");
        btnIniciar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                gameLoop.detenerEjecucion();
                GameLoop gameLoopAnterior = gameLoop; //almaceno la referencia al gameloop anterior

                if (!gameLoopAnterior.estaEjecutando())
                {
                    try
                    {
                        gameLoop = new GameLoop(gameLoopAnterior.getSuperficieDeDibujo()); //creo un nuevo gameloop
                        gameLoop.setFrecuencia(gameLoopAnterior.getFrecuencia()); //seteo frecuencia del anterior
                        inicializarModelo(); //inicializo modelo
                        inicializarVista();  //inicializo vista
                        inicializarControlador(); //inicializo controlador
                        agregarObservadores(); //agrego observadores al nuevo gameloop
                        gameLoopAnterior = null; //borro la referencia al gameloop anterior para garbage collector
                        gameLoop.iniciarEjecucion(); //inicio la ejecucion del nuevo gameloop

                    }
                    catch(Exception e)
                    {

                    }
                }

            }
        });
        btnIniciar.setBounds(270, 16, 90, 25);
        frame.getContentPane().add(btnIniciar);
        return btnIniciar;
    }

    private JLabel addLabelPuntaje()
    {
        JLabel label = new JLabel("Puntaje: 0");
        label.setVisible(true);
        label.setBounds(450,16,77,25);
        frame.getContentPane().add(label);
        return label;
    }



}
